Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-377.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 0.005.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

    1     2     3     4     5     6     7     8     9    10    11    12    13 
 2472  3209  6753  6990 18296   525  1348  4381  2819  8110   299   944  5063 
   14    15    16    17    18    19    20    21    22    23    24    25 
 2919  6230    26   171   740  6736  2726     8    62  1880  7140  5034 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("precip")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
         precip
[1,] -0.8062561
[2,]  0.2480394

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
  precip 
0.997619 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin             precip      
 Min.   : 1.00   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.00   1st Qu.:149.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.00   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.49   Mean   :200.5   Mean   :  98.99   Mean   : 15.53  
 3rd Qu.: 9.00   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.00   Max.   :403.0   Max.   : 254.00   Max.   :105.00  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0.000000   Median :   0.0000   Median :40.82   Median : -3.1742  
 Mean   :0.000297   Mean   :   0.4493   Mean   :39.65   Mean   : -3.4205  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :6.000000   Max.   :1834.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 418.6  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   : 1.000   Min.   :-42.0   Min.   :-108.00   Min.   :106.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:118.0   1st Qu.:  55.00   1st Qu.:113.0   1st Qu.:0  
 Median :10.000   Median :140.0   Median :  77.50   Median :123.0   Median :0  
 Mean   : 7.699   Mean   :142.6   Mean   :  76.52   Mean   :129.1   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:168.0   3rd Qu.: 102.00   3rd Qu.:140.0   3rd Qu.:0  
 Max.   :12.000   Max.   :326.0   Max.   : 207.00   Max.   :197.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:41.14   1st Qu.: -8.616   1st Qu.:  32.0  
 Median :  0.00   Median :42.43   Median : -7.456   Median : 261.0  
 Mean   :  3.63   Mean   :41.28   Mean   : -5.781   Mean   : 397.1  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.00   Max.   :43.57   Max.   :  3.035   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : 37.0   Min.   :-11.00   Min.   :200.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:113.5   1st Qu.: 63.00   1st Qu.:213.5   1st Qu.:0  
 Median : 6.500   Median :127.0   Median : 75.00   Median :229.0   Median :0  
 Mean   : 6.294   Mean   :156.7   Mean   : 88.91   Mean   :247.2   Mean   :0  
 3rd Qu.:10.750   3rd Qu.:174.0   3rd Qu.: 92.00   3rd Qu.:257.2   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:0    1st Qu.:41.67   1st Qu.: -8.624   1st Qu.: 261.0  
 Median :0    Median :42.24   Median : -8.411   Median : 263.0  
 Mean   :0    Mean   :40.80   Mean   : -6.919   Mean   : 477.8  
 3rd Qu.:0    3rd Qu.:42.89   3rd Qu.: -2.973   3rd Qu.: 370.0  
 Max.   :0    Max.   :43.36   Max.   :  2.825   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-47.0   Min.   :-115.00   Min.   : 42.00  
 1st Qu.: 3.000   1st Qu.:123.0   1st Qu.:  50.00   1st Qu.: 47.00  
 Median : 8.000   Median :154.0   Median :  78.00   Median : 54.00  
 Mean   : 6.946   Mean   :154.5   Mean   :  77.76   Mean   : 59.12  
 3rd Qu.:11.000   3rd Qu.:191.0   3rd Qu.: 110.00   3rd Qu.: 68.00  
 Max.   :12.000   Max.   :352.0   Max.   : 219.00   Max.   :105.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -6.2567  
 Median :0   Median :   0.000   Median :42.38   Median : -3.8189  
 Mean   :0   Mean   :   2.828   Mean   :41.28   Mean   : -3.6088  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:43.31   3rd Qu.:  0.3664  
 Max.   :0   Max.   :1834.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 143.0  
 Mean   : 448.5  
 3rd Qu.: 510.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.0   Min.   : 0.00  
 1st Qu.: 4.000   1st Qu.:153.0   1st Qu.:  53.0   1st Qu.: 2.00  
 Median : 6.000   Median :204.0   Median : 101.0   Median : 9.00  
 Mean   : 6.448   Mean   :204.8   Mean   : 100.9   Mean   :11.54  
 3rd Qu.: 9.000   3rd Qu.:260.0   3rd Qu.: 151.0   3rd Qu.:18.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :41.00  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.6156  
 Median :0.000000   Median :   0.0000   Median :40.72   Median : -3.1742  
 Mean   :0.000324   Mean   :   0.2316   Mean   :39.50   Mean   : -3.4033  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:41.88   3rd Qu.:  0.4914  
 Max.   :6.000000   Max.   :1494.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 415.9  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   : 1.000   Min.   :-42.0   Min.   :-108.00   Min.   :106.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:118.0   1st Qu.:  55.00   1st Qu.:113.0   1st Qu.:0  
 Median :10.000   Median :140.0   Median :  77.50   Median :123.0   Median :0  
 Mean   : 7.699   Mean   :142.6   Mean   :  76.52   Mean   :129.1   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:168.0   3rd Qu.: 102.00   3rd Qu.:140.0   3rd Qu.:0  
 Max.   :12.000   Max.   :326.0   Max.   : 207.00   Max.   :197.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:41.14   1st Qu.: -8.616   1st Qu.:  32.0  
 Median :  0.00   Median :42.43   Median : -7.456   Median : 261.0  
 Mean   :  3.63   Mean   :41.28   Mean   : -5.781   Mean   : 397.1  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.00   Max.   :43.57   Max.   :  3.035   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : 37.0   Min.   :-11.00   Min.   :200.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:113.5   1st Qu.: 63.00   1st Qu.:213.5   1st Qu.:0  
 Median : 6.500   Median :127.0   Median : 75.00   Median :229.0   Median :0  
 Mean   : 6.294   Mean   :156.7   Mean   : 88.91   Mean   :247.2   Mean   :0  
 3rd Qu.:10.750   3rd Qu.:174.0   3rd Qu.: 92.00   3rd Qu.:257.2   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:0    1st Qu.:41.67   1st Qu.: -8.624   1st Qu.: 261.0  
 Median :0    Median :42.24   Median : -8.411   Median : 263.0  
 Mean   :0    Mean   :40.80   Mean   : -6.919   Mean   : 477.8  
 3rd Qu.:0    3rd Qu.:42.89   3rd Qu.: -2.973   3rd Qu.: 370.0  
 Max.   :0    Max.   :43.36   Max.   :  2.825   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-47.0   Min.   :-115.00   Min.   : 42.00  
 1st Qu.: 3.000   1st Qu.:123.0   1st Qu.:  50.00   1st Qu.: 47.00  
 Median : 8.000   Median :154.0   Median :  78.00   Median : 54.00  
 Mean   : 6.946   Mean   :154.5   Mean   :  77.76   Mean   : 59.12  
 3rd Qu.:11.000   3rd Qu.:191.0   3rd Qu.: 110.00   3rd Qu.: 68.00  
 Max.   :12.000   Max.   :352.0   Max.   : 219.00   Max.   :105.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -6.2567  
 Median :0   Median :   0.000   Median :42.38   Median : -3.8189  
 Mean   :0   Mean   :   2.828   Mean   :41.28   Mean   : -3.6088  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:43.31   3rd Qu.:  0.3664  
 Max.   :0   Max.   :1834.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 143.0  
 Mean   : 448.5  
 3rd Qu.: 510.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.0   Min.   : 0.00  
 1st Qu.: 4.000   1st Qu.:153.0   1st Qu.:  53.0   1st Qu.: 2.00  
 Median : 6.000   Median :204.0   Median : 101.0   Median : 9.00  
 Mean   : 6.448   Mean   :204.8   Mean   : 100.9   Mean   :11.54  
 3rd Qu.: 9.000   3rd Qu.:260.0   3rd Qu.: 151.0   3rd Qu.:18.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :41.00  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.6156  
 Median :0.000000   Median :   0.0000   Median :40.72   Median : -3.1742  
 Mean   :0.000324   Mean   :   0.2316   Mean   :39.50   Mean   : -3.4033  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:41.88   3rd Qu.:  0.4914  
 Max.   :6.000000   Max.   :1494.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 415.9  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   : 1.000   Min.   :-42.0   Min.   :-108.00   Min.   :106.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:118.0   1st Qu.:  55.00   1st Qu.:113.0   1st Qu.:0  
 Median :10.000   Median :140.0   Median :  77.50   Median :123.0   Median :0  
 Mean   : 7.699   Mean   :142.6   Mean   :  76.52   Mean   :129.1   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:168.0   3rd Qu.: 102.00   3rd Qu.:140.0   3rd Qu.:0  
 Max.   :12.000   Max.   :326.0   Max.   : 207.00   Max.   :197.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:41.14   1st Qu.: -8.616   1st Qu.:  32.0  
 Median :  0.00   Median :42.43   Median : -7.456   Median : 261.0  
 Mean   :  3.63   Mean   :41.28   Mean   : -5.781   Mean   : 397.1  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.00   Max.   :43.57   Max.   :  3.035   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   :104.0   Min.   : 23.00   Min.   :200.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:113.5   1st Qu.: 63.00   1st Qu.:209.2   1st Qu.:0  
 Median : 6.500   Median :125.5   Median : 73.50   Median :222.0   Median :0  
 Mean   : 6.346   Mean   :156.5   Mean   : 88.35   Mean   :223.8   Mean   :0  
 3rd Qu.:10.750   3rd Qu.:154.5   3rd Qu.: 91.50   3rd Qu.:233.2   3rd Qu.:0  
 Max.   :12.000   Max.   :331.0   Max.   :223.00   Max.   :259.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :  19.0  
 1st Qu.:0    1st Qu.:41.67   1st Qu.: -8.624   1st Qu.: 261.0  
 Median :0    Median :42.24   Median : -8.411   Median : 263.0  
 Mean   :0    Mean   :40.89   Mean   : -6.862   Mean   : 473.1  
 3rd Qu.:0    3rd Qu.:42.89   3rd Qu.: -3.579   3rd Qu.: 370.0  
 Max.   :0    Max.   :43.30   Max.   :  2.825   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : 37.0   Min.   :-11.00   Min.   :279.0   Min.   :0  
 1st Qu.: 2.750   1st Qu.:108.2   1st Qu.: 49.75   1st Qu.:294.2   1st Qu.:0  
 Median : 5.500   Median :127.0   Median : 78.50   Median :307.0   Median :0  
 Mean   : 6.125   Mean   :157.5   Mean   : 90.75   Mean   :323.1   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:194.0   3rd Qu.:137.25   3rd Qu.:332.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :204.00   Max.   :422.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:0    1st Qu.:41.42   1st Qu.: -8.649   1st Qu.:  19.0  
 Median :0    Median :42.33   Median : -8.517   Median : 262.0  
 Mean   :0    Mean   :40.50   Mean   : -7.103   Mean   : 493.2  
 3rd Qu.:0    3rd Qu.:42.54   3rd Qu.: -2.827   3rd Qu.: 437.2  
 Max.   :0    Max.   :43.36   Max.   : -1.033   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-47.0   Min.   :-115.00   Min.   : 42.00  
 1st Qu.: 3.000   1st Qu.:123.0   1st Qu.:  50.00   1st Qu.: 47.00  
 Median : 8.000   Median :154.0   Median :  78.00   Median : 54.00  
 Mean   : 6.946   Mean   :154.5   Mean   :  77.76   Mean   : 59.12  
 3rd Qu.:11.000   3rd Qu.:191.0   3rd Qu.: 110.00   3rd Qu.: 68.00  
 Max.   :12.000   Max.   :352.0   Max.   : 219.00   Max.   :105.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -6.2567  
 Median :0   Median :   0.000   Median :42.38   Median : -3.8189  
 Mean   :0   Mean   :   2.828   Mean   :41.28   Mean   : -3.6088  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:43.31   3rd Qu.:  0.3664  
 Max.   :0   Max.   :1834.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 143.0  
 Mean   : 448.5  
 3rd Qu.: 510.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip     
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.0   Min.   : 0.00  
 1st Qu.: 4.000   1st Qu.:153.0   1st Qu.:  53.0   1st Qu.: 2.00  
 Median : 6.000   Median :204.0   Median : 101.0   Median : 9.00  
 Mean   : 6.448   Mean   :204.8   Mean   : 100.9   Mean   :11.54  
 3rd Qu.: 9.000   3rd Qu.:260.0   3rd Qu.: 151.0   3rd Qu.:18.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :41.00  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:37.98   1st Qu.: -5.6156  
 Median :0.000000   Median :   0.0000   Median :40.72   Median : -3.1742  
 Mean   :0.000324   Mean   :   0.2316   Mean   :39.50   Mean   : -3.4033  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:41.88   3rd Qu.:  0.4914  
 Max.   :6.000000   Max.   :1494.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 415.9  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-42.0   Min.   :-108.00   Min.   :106.0   Min.   :0  
 1st Qu.: 3.00   1st Qu.:119.0   1st Qu.:  56.25   1st Qu.:112.0   1st Qu.:0  
 Median :10.00   Median :142.0   Median :  79.00   Median :120.0   Median :0  
 Mean   : 7.66   Mean   :144.7   Mean   :  77.92   Mean   :123.4   Mean   :0  
 3rd Qu.:11.00   3rd Qu.:170.0   3rd Qu.: 104.00   3rd Qu.:133.0   3rd Qu.:0  
 Max.   :12.00   Max.   :326.0   Max.   : 207.00   Max.   :155.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:41.29   1st Qu.: -8.616   1st Qu.:  32.0  
 Median :  0.00   Median :42.43   Median : -7.202   Median : 251.0  
 Mean   :  2.57   Mean   :41.32   Mean   : -5.731   Mean   : 375.9  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.00   Max.   :43.57   Max.   :  3.035   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   :104.0   Min.   : 23.00   Min.   :200.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:113.5   1st Qu.: 63.00   1st Qu.:209.2   1st Qu.:0  
 Median : 6.500   Median :125.5   Median : 73.50   Median :222.0   Median :0  
 Mean   : 6.346   Mean   :156.5   Mean   : 88.35   Mean   :223.8   Mean   :0  
 3rd Qu.:10.750   3rd Qu.:154.5   3rd Qu.: 91.50   3rd Qu.:233.2   3rd Qu.:0  
 Max.   :12.000   Max.   :331.0   Max.   :223.00   Max.   :259.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :  19.0  
 1st Qu.:0    1st Qu.:41.67   1st Qu.: -8.624   1st Qu.: 261.0  
 Median :0    Median :42.24   Median : -8.411   Median : 263.0  
 Mean   :0    Mean   :40.89   Mean   : -6.862   Mean   : 473.1  
 3rd Qu.:0    3rd Qu.:42.89   3rd Qu.: -3.579   3rd Qu.: 370.0  
 Max.   :0    Max.   :43.30   Max.   :  2.825   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : 37.0   Min.   :-11.00   Min.   :279.0   Min.   :0  
 1st Qu.: 2.750   1st Qu.:108.2   1st Qu.: 49.75   1st Qu.:294.2   1st Qu.:0  
 Median : 5.500   Median :127.0   Median : 78.50   Median :307.0   Median :0  
 Mean   : 6.125   Mean   :157.5   Mean   : 90.75   Mean   :323.1   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:194.0   3rd Qu.:137.25   3rd Qu.:332.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :204.00   Max.   :422.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:0    1st Qu.:41.42   1st Qu.: -8.649   1st Qu.:  19.0  
 Median :0    Median :42.33   Median : -8.517   Median : 262.0  
 Mean   :0    Mean   :40.50   Mean   : -7.103   Mean   : 493.2  
 3rd Qu.:0    3rd Qu.:42.54   3rd Qu.: -2.827   3rd Qu.: 437.2  
 Max.   :0    Max.   :43.36   Max.   : -1.033   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt       tmax            tmin            precip          nevada 
 Min.   : 1   Min.   : -8.0   Min.   :-58.00   Min.   :156.0   Min.   :0  
 1st Qu.: 3   1st Qu.:106.2   1st Qu.: 43.25   1st Qu.:163.0   1st Qu.:0  
 Median :11   Median :131.5   Median : 69.50   Median :171.0   Median :0  
 Mean   : 8   Mean   :126.8   Mean   : 65.87   Mean   :173.0   Mean   :0  
 3rd Qu.:11   3rd Qu.:147.8   3rd Qu.: 90.75   3rd Qu.:183.8   3rd Qu.:0  
 Max.   :12   Max.   :320.0   Max.   :189.00   Max.   :197.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud       
 Min.   :  0.00   Min.   :28.31   Min.   :-16.499   Min.   :   4.00  
 1st Qu.:  0.00   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  71.95  
 Median :  0.00   Median :42.24   Median : -8.411   Median : 261.00  
 Mean   : 11.66   Mean   :40.95   Mean   : -6.164   Mean   : 558.26  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -3.876   3rd Qu.: 370.00  
 Max.   :607.00   Max.   :43.46   Max.   :  2.825   Max.   :2400.00  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   : 1.000   Min.   :-47.0   Min.   :-115.00   Min.   :42.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:125.0   1st Qu.:  50.00   1st Qu.:46.00   1st Qu.:0  
 Median : 7.000   Median :155.0   Median :  79.00   Median :52.00   Median :0  
 Mean   : 6.888   Mean   :156.1   Mean   :  78.11   Mean   :53.75   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:193.0   3rd Qu.: 110.00   3rd Qu.:60.00   3rd Qu.:0  
 Max.   :12.000   Max.   :352.0   Max.   : 219.00   Max.   :75.00   Max.   :0  
   prof_nieve        longitud        latitud            altitud      
 Min.   :   0.0   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:   0.0   1st Qu.:40.78   1st Qu.: -6.0442   1st Qu.:  42.0  
 Median :   0.0   Median :42.38   Median : -3.7994   Median : 143.0  
 Mean   :   2.5   Mean   :41.27   Mean   : -3.4685   Mean   : 451.9  
 3rd Qu.:   0.0   3rd Qu.:43.31   3rd Qu.:  0.4914   3rd Qu.: 513.0  
 Max.   :1834.0   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip     
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :20.00  
 1st Qu.: 3.000   1st Qu.:137.0   1st Qu.:  50.00   1st Qu.:23.00  
 Median : 6.000   Median :174.0   Median :  83.00   Median :27.00  
 Mean   : 6.469   Mean   :175.1   Mean   :  83.95   Mean   :28.26  
 3rd Qu.:10.000   3rd Qu.:216.0   3rd Qu.: 120.00   3rd Qu.:33.00  
 Max.   :12.000   Max.   :355.0   Max.   : 244.00   Max.   :41.00  
     nevada            prof_nieve           longitud        latitud        
 Min.   :0.0000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:   0.0000   1st Qu.:39.95   1st Qu.: -5.6417  
 Median :0.0000000   Median :   0.0000   Median :41.63   Median : -2.9056  
 Mean   :0.0001032   Mean   :   0.6065   Mean   :40.79   Mean   : -2.8952  
 3rd Qu.:0.0000000   3rd Qu.:   0.0000   3rd Qu.:42.68   3rd Qu.:  0.7106  
 Max.   :2.0000000   Max.   :1494.0000   Max.   :43.57   Max.   :  4.2156  
    altitud    
 Min.   :   1  
 1st Qu.:  52  
 Median : 261  
 Mean   : 468  
 3rd Qu.: 667  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin            precip      
 Min.   : 1.000   Min.   :-46.0   Min.   :-114.0   Min.   : 0.000  
 1st Qu.: 4.000   1st Qu.:160.0   1st Qu.:  54.0   1st Qu.: 1.000  
 Median : 7.000   Median :216.0   Median : 109.0   Median : 6.000  
 Mean   : 6.442   Mean   :213.3   Mean   : 105.8   Mean   : 6.701  
 3rd Qu.: 9.000   3rd Qu.:271.0   3rd Qu.: 159.0   3rd Qu.:11.000  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :19.000  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:37.84   1st Qu.: -5.6156  
 Median :0.000000   Median :   0.0000   Median :40.47   Median : -3.1742  
 Mean   :0.000388   Mean   :   0.1231   Mean   :39.13   Mean   : -3.5503  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:41.66   3rd Qu.:  0.4731  
 Max.   :6.000000   Max.   :1073.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  35.0  
 Median : 200.0  
 Mean   : 400.8  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax          tmin             precip           nevada 
 Min.   : 1.000   Min.   :-35   Min.   :-104.00   Min.   : 76.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:118   1st Qu.:  50.00   1st Qu.: 80.00   1st Qu.:0  
 Median : 9.000   Median :147   Median :  77.00   Median : 86.00   Median :0  
 Mean   : 7.248   Mean   :146   Mean   :  75.92   Mean   : 87.35   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:181   3rd Qu.: 109.00   3rd Qu.: 94.00   3rd Qu.:0  
 Max.   :12.000   Max.   :307   Max.   : 219.00   Max.   :105.00   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -8.411   1st Qu.:  34.0  
 Median :  0.000   Median :42.43   Median : -4.010   Median : 143.0  
 Mean   :  4.551   Mean   :41.35   Mean   : -4.345   Mean   : 430.3  
 3rd Qu.:  0.000   3rd Qu.:43.31   3rd Qu.: -1.787   3rd Qu.: 370.0  
 Max.   :784.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-42.0   Min.   :-108.00   Min.   :106.0   Min.   :0  
 1st Qu.: 3.00   1st Qu.:119.0   1st Qu.:  56.25   1st Qu.:112.0   1st Qu.:0  
 Median :10.00   Median :142.0   Median :  79.00   Median :120.0   Median :0  
 Mean   : 7.66   Mean   :144.7   Mean   :  77.92   Mean   :123.4   Mean   :0  
 3rd Qu.:11.00   3rd Qu.:170.0   3rd Qu.: 104.00   3rd Qu.:133.0   3rd Qu.:0  
 Max.   :12.00   Max.   :326.0   Max.   : 207.00   Max.   :155.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:41.29   1st Qu.: -8.616   1st Qu.:  32.0  
 Median :  0.00   Median :42.43   Median : -7.202   Median : 251.0  
 Mean   :  2.57   Mean   :41.32   Mean   : -5.731   Mean   : 375.9  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.00   Max.   :43.57   Max.   :  3.035   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   :104.0   Min.   : 23.00   Min.   :200.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:113.5   1st Qu.: 63.00   1st Qu.:209.2   1st Qu.:0  
 Median : 6.500   Median :125.5   Median : 73.50   Median :222.0   Median :0  
 Mean   : 6.346   Mean   :156.5   Mean   : 88.35   Mean   :223.8   Mean   :0  
 3rd Qu.:10.750   3rd Qu.:154.5   3rd Qu.: 91.50   3rd Qu.:233.2   3rd Qu.:0  
 Max.   :12.000   Max.   :331.0   Max.   :223.00   Max.   :259.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :  19.0  
 1st Qu.:0    1st Qu.:41.67   1st Qu.: -8.624   1st Qu.: 261.0  
 Median :0    Median :42.24   Median : -8.411   Median : 263.0  
 Mean   :0    Mean   :40.89   Mean   : -6.862   Mean   : 473.1  
 3rd Qu.:0    3rd Qu.:42.89   3rd Qu.: -3.579   3rd Qu.: 370.0  
 Max.   :0    Max.   :43.30   Max.   :  2.825   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : 37.0   Min.   :-11.00   Min.   :279.0   Min.   :0  
 1st Qu.: 2.750   1st Qu.:108.2   1st Qu.: 49.75   1st Qu.:294.2   1st Qu.:0  
 Median : 5.500   Median :127.0   Median : 78.50   Median :307.0   Median :0  
 Mean   : 6.125   Mean   :157.5   Mean   : 90.75   Mean   :323.1   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:194.0   3rd Qu.:137.25   3rd Qu.:332.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :204.00   Max.   :422.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:0    1st Qu.:41.42   1st Qu.: -8.649   1st Qu.:  19.0  
 Median :0    Median :42.33   Median : -8.517   Median : 262.0  
 Mean   :0    Mean   :40.50   Mean   : -7.103   Mean   : 493.2  
 3rd Qu.:0    3rd Qu.:42.54   3rd Qu.: -2.827   3rd Qu.: 437.2  
 Max.   :0    Max.   :43.36   Max.   : -1.033   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt       tmax            tmin            precip          nevada 
 Min.   : 1   Min.   : -8.0   Min.   :-58.00   Min.   :156.0   Min.   :0  
 1st Qu.: 3   1st Qu.:106.2   1st Qu.: 43.25   1st Qu.:163.0   1st Qu.:0  
 Median :11   Median :131.5   Median : 69.50   Median :171.0   Median :0  
 Mean   : 8   Mean   :126.8   Mean   : 65.87   Mean   :173.0   Mean   :0  
 3rd Qu.:11   3rd Qu.:147.8   3rd Qu.: 90.75   3rd Qu.:183.8   3rd Qu.:0  
 Max.   :12   Max.   :320.0   Max.   :189.00   Max.   :197.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud       
 Min.   :  0.00   Min.   :28.31   Min.   :-16.499   Min.   :   4.00  
 1st Qu.:  0.00   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  71.95  
 Median :  0.00   Median :42.24   Median : -8.411   Median : 261.00  
 Mean   : 11.66   Mean   :40.95   Mean   : -6.164   Mean   : 558.26  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -3.876   3rd Qu.: 370.00  
 Max.   :607.00   Max.   :43.46   Max.   :  2.825   Max.   :2400.00  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   : 1.000   Min.   :-39.0   Min.   :-104.00   Min.   :42.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:125.0   1st Qu.:  50.00   1st Qu.:44.00   1st Qu.:0  
 Median : 7.000   Median :158.0   Median :  79.00   Median :48.00   Median :0  
 Mean   : 6.836   Mean   :158.7   Mean   :  78.57   Mean   :48.03   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:196.0   3rd Qu.: 111.00   3rd Qu.:51.00   3rd Qu.:0  
 Max.   :12.000   Max.   :352.0   Max.   : 219.00   Max.   :56.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.78   1st Qu.: -5.8792   1st Qu.:  44.0  
 Median :   0.000   Median :42.33   Median : -3.7003   Median : 176.0  
 Mean   :   2.674   Mean   :41.26   Mean   : -3.2281   Mean   : 460.6  
 3rd Qu.:   0.000   3rd Qu.:43.31   3rd Qu.:  0.7292   3rd Qu.: 534.0  
 Max.   :1834.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip     
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :20.00  
 1st Qu.: 3.000   1st Qu.:137.0   1st Qu.:  50.00   1st Qu.:23.00  
 Median : 6.000   Median :174.0   Median :  83.00   Median :27.00  
 Mean   : 6.469   Mean   :175.1   Mean   :  83.95   Mean   :28.26  
 3rd Qu.:10.000   3rd Qu.:216.0   3rd Qu.: 120.00   3rd Qu.:33.00  
 Max.   :12.000   Max.   :355.0   Max.   : 244.00   Max.   :41.00  
     nevada            prof_nieve           longitud        latitud        
 Min.   :0.0000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:   0.0000   1st Qu.:39.95   1st Qu.: -5.6417  
 Median :0.0000000   Median :   0.0000   Median :41.63   Median : -2.9056  
 Mean   :0.0001032   Mean   :   0.6065   Mean   :40.79   Mean   : -2.8952  
 3rd Qu.:0.0000000   3rd Qu.:   0.0000   3rd Qu.:42.68   3rd Qu.:  0.7106  
 Max.   :2.0000000   Max.   :1494.0000   Max.   :43.57   Max.   :  4.2156  
    altitud    
 Min.   :   1  
 1st Qu.:  52  
 Median : 261  
 Mean   : 468  
 3rd Qu.: 667  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin            precip      
 Min.   : 1.000   Min.   :-46.0   Min.   :-114.0   Min.   : 0.000  
 1st Qu.: 4.000   1st Qu.:160.0   1st Qu.:  54.0   1st Qu.: 1.000  
 Median : 7.000   Median :216.0   Median : 109.0   Median : 6.000  
 Mean   : 6.442   Mean   :213.3   Mean   : 105.8   Mean   : 6.701  
 3rd Qu.: 9.000   3rd Qu.:271.0   3rd Qu.: 159.0   3rd Qu.:11.000  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :19.000  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:37.84   1st Qu.: -5.6156  
 Median :0.000000   Median :   0.0000   Median :40.47   Median : -3.1742  
 Mean   :0.000388   Mean   :   0.1231   Mean   :39.13   Mean   : -3.5503  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:41.66   3rd Qu.:  0.4731  
 Max.   :6.000000   Max.   :1073.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  35.0  
 Median : 200.0  
 Mean   : 400.8  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax          tmin             precip           nevada 
 Min.   : 1.000   Min.   :-35   Min.   :-104.00   Min.   : 76.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:118   1st Qu.:  50.00   1st Qu.: 80.00   1st Qu.:0  
 Median : 9.000   Median :147   Median :  77.00   Median : 86.00   Median :0  
 Mean   : 7.248   Mean   :146   Mean   :  75.92   Mean   : 87.35   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:181   3rd Qu.: 109.00   3rd Qu.: 94.00   3rd Qu.:0  
 Max.   :12.000   Max.   :307   Max.   : 219.00   Max.   :105.00   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -8.411   1st Qu.:  34.0  
 Median :  0.000   Median :42.43   Median : -4.010   Median : 143.0  
 Mean   :  4.551   Mean   :41.35   Mean   : -4.345   Mean   : 430.3  
 3rd Qu.:  0.000   3rd Qu.:43.31   3rd Qu.: -1.787   3rd Qu.: 370.0  
 Max.   :784.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin             precip         nevada 
 Min.   : 1.000   Min.   :-47.0   Min.   :-115.00   Min.   :57.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:123.0   1st Qu.:  51.00   1st Qu.:60.0   1st Qu.:0  
 Median : 9.000   Median :151.0   Median :  78.00   Median :64.0   Median :0  
 Mean   : 6.986   Mean   :151.3   Mean   :  77.22   Mean   :64.6   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:187.0   3rd Qu.: 108.25   3rd Qu.:69.0   3rd Qu.:0  
 Max.   :12.000   Max.   :336.0   Max.   : 215.00   Max.   :75.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -6.829   1st Qu.:  42.0  
 Median :  0.000   Median :42.44   Median : -3.819   Median : 127.0  
 Mean   :  2.168   Mean   :41.29   Mean   : -3.925   Mean   : 435.5  
 3rd Qu.:  0.000   3rd Qu.:43.31   3rd Qu.: -1.636   3rd Qu.: 442.0  
 Max.   :606.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   :-42.0   Min.   :-108.0   Min.   :106.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:120.5   1st Qu.:  57.0   1st Qu.:110.0   1st Qu.:0  
 Median :10.000   Median :148.0   Median :  82.0   Median :114.0   Median :0  
 Mean   : 7.729   Mean   :147.6   Mean   :  79.4   Mean   :114.7   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:176.5   3rd Qu.: 108.0   3rd Qu.:120.0   3rd Qu.:0  
 Max.   :12.000   Max.   :292.0   Max.   : 202.0   Max.   :126.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.92   Min.   :-17.755   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.82   1st Qu.: -8.616   1st Qu.:  27.0  
 Median :  0.000   Median :42.44   Median : -5.879   Median : 127.0  
 Mean   :  3.535   Mean   :41.27   Mean   : -5.412   Mean   : 380.1  
 3rd Qu.:  0.000   3rd Qu.:43.00   3rd Qu.: -1.787   3rd Qu.: 370.0  
 Max.   :892.000   Max.   :43.57   Max.   :  3.035   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   :104.0   Min.   : 23.00   Min.   :200.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:113.5   1st Qu.: 63.00   1st Qu.:209.2   1st Qu.:0  
 Median : 6.500   Median :125.5   Median : 73.50   Median :222.0   Median :0  
 Mean   : 6.346   Mean   :156.5   Mean   : 88.35   Mean   :223.8   Mean   :0  
 3rd Qu.:10.750   3rd Qu.:154.5   3rd Qu.: 91.50   3rd Qu.:233.2   3rd Qu.:0  
 Max.   :12.000   Max.   :331.0   Max.   :223.00   Max.   :259.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :  19.0  
 1st Qu.:0    1st Qu.:41.67   1st Qu.: -8.624   1st Qu.: 261.0  
 Median :0    Median :42.24   Median : -8.411   Median : 263.0  
 Mean   :0    Mean   :40.89   Mean   : -6.862   Mean   : 473.1  
 3rd Qu.:0    3rd Qu.:42.89   3rd Qu.: -3.579   3rd Qu.: 370.0  
 Max.   :0    Max.   :43.30   Max.   :  2.825   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -4.0   Min.   :-48.00   Min.   :127.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:117.5   1st Qu.: 55.50   1st Qu.:132.0   1st Qu.:0  
 Median :10.000   Median :133.0   Median : 71.00   Median :138.0   Median :0  
 Mean   : 7.538   Mean   :139.5   Mean   : 75.32   Mean   :138.5   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:165.0   3rd Qu.: 96.50   3rd Qu.:145.0   3rd Qu.:0  
 Max.   :12.000   Max.   :326.0   Max.   :207.00   Max.   :155.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   : 0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.: 0.000   1st Qu.:41.81   1st Qu.: -8.624   1st Qu.:  43.3  
 Median : 0.000   Median :42.43   Median : -8.411   Median : 261.0  
 Mean   : 0.883   Mean   :41.40   Mean   : -6.288   Mean   : 368.5  
 3rd Qu.: 0.000   3rd Qu.:42.89   3rd Qu.: -3.831   3rd Qu.: 370.0  
 Max.   :79.000   Max.   :43.49   Max.   :  2.827   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : 37.0   Min.   :-11.00   Min.   :279.0   Min.   :0  
 1st Qu.: 2.750   1st Qu.:108.2   1st Qu.: 49.75   1st Qu.:294.2   1st Qu.:0  
 Median : 5.500   Median :127.0   Median : 78.50   Median :307.0   Median :0  
 Mean   : 6.125   Mean   :157.5   Mean   : 90.75   Mean   :323.1   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:194.0   3rd Qu.:137.25   3rd Qu.:332.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :204.00   Max.   :422.0   Max.   :0  
   prof_nieve    longitud        latitud           altitud      
 Min.   :0    Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:0    1st Qu.:41.42   1st Qu.: -8.649   1st Qu.:  19.0  
 Median :0    Median :42.33   Median : -8.517   Median : 262.0  
 Mean   :0    Mean   :40.50   Mean   : -7.103   Mean   : 493.2  
 3rd Qu.:0    3rd Qu.:42.54   3rd Qu.: -2.827   3rd Qu.: 437.2  
 Max.   :0    Max.   :43.36   Max.   : -1.033   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt       tmax            tmin            precip          nevada 
 Min.   : 1   Min.   : -8.0   Min.   :-58.00   Min.   :156.0   Min.   :0  
 1st Qu.: 3   1st Qu.:106.2   1st Qu.: 43.25   1st Qu.:163.0   1st Qu.:0  
 Median :11   Median :131.5   Median : 69.50   Median :171.0   Median :0  
 Mean   : 8   Mean   :126.8   Mean   : 65.87   Mean   :173.0   Mean   :0  
 3rd Qu.:11   3rd Qu.:147.8   3rd Qu.: 90.75   3rd Qu.:183.8   3rd Qu.:0  
 Max.   :12   Max.   :320.0   Max.   :189.00   Max.   :197.0   Max.   :0  
   prof_nieve        longitud        latitud           altitud       
 Min.   :  0.00   Min.   :28.31   Min.   :-16.499   Min.   :   4.00  
 1st Qu.:  0.00   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  71.95  
 Median :  0.00   Median :42.24   Median : -8.411   Median : 261.00  
 Mean   : 11.66   Mean   :40.95   Mean   : -6.164   Mean   : 558.26  
 3rd Qu.:  0.00   3rd Qu.:42.89   3rd Qu.: -3.876   3rd Qu.: 370.00  
 Max.   :607.00   Max.   :43.46   Max.   :  2.825   Max.   :2400.00  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAzNzcKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogcHJlY2lwCiogRGltZW5zaW9uZXMgZGVsIG1hcGE6IDUsNQoqIEl0ZXJhY2lvbmVzOiAxMDAwCiogUGFyw6FtZXRyb3MgYWRpY2lvbmFsZXM6IAoKYGBge3J9CnNvdXJjZSgiLi4vLi4vbGliL3NvbS11dGlscy5SIikKc291cmNlKCIuLi8uLi9saWIvbWFwcy11dGlscy5SIikKYGBgCgojIENhcmdhIGRlbCBtb2RlbG8gZGVzZGUgZGlzY28KCmBgYHtyfQptcHIuc2V0X2Jhc2VfcGF0aF9hbmFseXNpcygpCm1vZGVsIDwtIG1wci5sb2FkX21vZGVsKCJzb20tMzc3LnJkcy54eiIpCnN1bW1hcnkobW9kZWwpCmBgYAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNoYW5nZXMiKQpgYGAKCiMgQ2FyZ2EgZGVsIGRhdGFzZXQgZGUgZW50cmFkYQoKYGBge3J9CmRmIDwtIG1wci5sb2FkX2RhdGEoImRhdG9zX21lcy5jc3YueHoiKQpgYGAKCmBgYHtyfQpkZgpgYGAKCmBgYHtyfQpzdW1tYXJ5KGRmKQpgYGAKCiMgQ2FyZ2EgZGUgbG9zIG1hcGFzCgpgYGB7cn0Kd29ybGQgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKc3BhaW4gPC0gc3Vic2V0KHdvcmxkLCBhZG1pbiA9PSAiU3BhaW4iKQpgYGAKCiMgTWFwYSBkZSBkZW5zaWRhZAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNvdW50Iiwgc2hhcGUgPSAic3RyYWlnaHQiLCBwYWxldHRlLm5hbWUgPSBtcHIuZGVncmFkZS5ibGV1KQpgYGAKCk7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2VsZGE6CgpgYGB7cn0KbmIgPC0gdGFibGUobW9kZWwkdW5pdC5jbGFzc2lmKQpwcmludChuYikKYGBgCkNvbXByb2JhY2nDs24gZGUgbm9kb3MgdmFjw61vczoKCmBgYHtyfQpkaW1fbW9kZWwgPC0gNSo1OwpsZW5fbmIgPSBsZW5ndGgobmIpOwplbXB0eV9ub2RlcyA8LSBkaW1fbW9kZWwgIT0gbGVuX25iOwppZiAoZW1wdHlfbm9kZXMpIHsKICBwcmludChwYXN0ZSgiW1dhcm5pbmddIEV4aXN0ZW4gbm9kb3MgdmFjw61vczogIiwgbGVuX25iLCAiLyIsIGRpbV9tb2RlbCkpCn0KYGBgCgojIE1hcGEgZGUgZGlzdGFuY2lhIGVudHJlIHZlY2lub3MKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJkaXN0Lm5laWdoYm91cnMiLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyBJbmZsdWVuY2lhIGRlIGxhcyB2YXJpYWJsZXMKCmBgYHtyfQptb2RlbF9jb2xuYW1lcyA9IGMoInByZWNpcCIpCm1vZGVsX25jb2wgPSBsZW5ndGgobW9kZWxfY29sbmFtZXMpCmBgYAoKIyMgTWFwYSBkZSB2YXJpYWJsZXMuCgpgYGB7cn0KcGxvdChtb2RlbCwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMjIE1hcGEgZGUgY2Fsb3IgcG9yIHZhcmlhYmxlCgpgYGB7cn0KcGFyKG1mcm93PWMoMyw0KSkKZm9yIChqIGluIDE6bW9kZWxfbmNvbCkgewogIHBsb3QobW9kZWwsIHR5cGU9InByb3BlcnR5IiwgcHJvcGVydHk9Z2V0Q29kZXMobW9kZWwsMSlbLGpdLAogICAgcGFsZXR0ZS5uYW1lPW1wci5jb29sQmx1ZUhvdFJlZCwKICAgIG1haW49bW9kZWxfY29sbmFtZXNbal0sCiAgICBjZXg9MC41LCBzaGFwZSA9ICJzdHJhaWdodCIpCn0KYGBgCgojIyBDb3JyZWxhY2nDs24gcGFyYSBjYWRhIGNvbHVtbmEgZGVsIHZlY3RvciBkZSBub2RvcwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBjb3IgPC0gYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksIDIsIG1wci53ZWlnaHRlZC5jb3JyZWxhdGlvbiwgdz1uYiwgc29tPW1vZGVsKQogIHByaW50KGNvcikKfQpgYGAKClJlcHJlc2VudGFjacOzbiBkZSBjYWRhIHZhcmlhYmxlIGVuIHVuIG1hcGEgZGUgZmFjdG9yZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBhcihtZnJvdz1jKDEsMSkpCiAgcGxvdChjb3JbMSxdLCBjb3JbMixdLCB4bGltPWMoLTEsMSksIHlsaW09YygtMSwxKSwgdHlwZT0ibiIpCiAgbGluZXMoYygtMSwxKSxjKDAsMCkpCiAgbGluZXMoYygwLDApLGMoLTEsMSkpCiAgdGV4dChjb3JbMSxdLCBjb3JbMixdLCBsYWJlbHM9bW9kZWxfY29sbmFtZXMsIGNleD0wLjc1KQogIHN5bWJvbHMoMCwwLGNpcmNsZXM9MSxpbmNoZXM9RixhZGQ9VCkKfQpgYGAKCkltcG9ydGFuY2lhIGRlIGNhZGEgdmFyaWFibGUgLSB2YXJpYW56YSBwb25kZXJhZGEgcG9yIGVsIHRhbWHDsW8gZGUgbGEgY2VsZGE6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHNpZ21hMiA8LSBzcXJ0KGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLDIsZnVuY3Rpb24oeCxlZmZlY3RpZikKICAgICB7bTwtc3VtKGVmZmVjdGlmKih4LXdlaWdodGVkLm1lYW4oeCxlZmZlY3RpZikpXjIpLyhzdW0oZWZmZWN0aWYpLTEpfSwKICAgICBlZmZlY3RpZj1uYikpCiAgcHJpbnQoc29ydChzaWdtYTIsZGVjcmVhc2luZz1UKSkKfQpgYGAKCiMgQ2x1c3RlcmluZwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBoYWMgPC0gbXByLmhhYyhtb2RlbCwgbmIpCn0KYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAzIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MykKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTMpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTQpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz00KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA1IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NSkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTUpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA2IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NikKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTYpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgOCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTgpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz04KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMTAgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0xMCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTEwKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQogIGRmLmNsdXN0ZXIwOSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTkpCiAgZGYuY2x1c3RlcjEwIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MTApCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDkgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjEwIDwtIHNlbGVjdChkZi5jbHVzdGVyMTAsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0sIGRpbShkZi5jbHVzdGVyMDkpWzFdLCBkaW0oZGYuY2x1c3RlcjEwKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiLCAiY2x1c3RlcjA5IiwgImNsdXN0ZXIxMCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMTApCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMTApCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQogIGRmLmNsdXN0ZXIwOS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA5KQogIGRmLmNsdXN0ZXIxMC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjEwKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA5Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjEwLmdyb3VwZWQpCmBgYAo=